package tpcomp2010.estructura;

import java.util.Stack;

/**
 * Clase encargada de convertir la cadena de entrada de Infija a Postfija.
 * Ejemplo: infija   -> a.b*|a
 *          postfija -> ab*.a|
 * 
 */
public class InfijaPostfija {

    private Stack<String> stack;
    private String infixExp;
    private String postfixExp = "";
    private String alpha;
    public Boolean ok;

    /** Constructor de la clase InfijaPostfija.
     * Recibe una expresion y el alfabeto, y a partir eso genera la cadena
     * postfija, o un error en caso de que la expresion contenga un simbolo
     * que no pertenezca al alfabeto.
     */
    public InfijaPostfija(String exp, String alpha){
        infixExp = exp;
        this.alpha = alpha;
        this.ok = true;
        stack = new Stack<String>();
        
        String str = "";
        for (int i = 0; i < infixExp.length(); i++) {
            str = infixExp.substring(i, i + 1);

            //if (str.matches("[a-zA-Z]|\\d")) {
            if (this.alpha.indexOf(str) != -1) {
                postfixExp += str;
            } else if (isLeftParenthesis(str)) {
                stack.push(str);
            } else if (isRightParenthesis(str)) {
                String elemPila = stack.pop();
                while (!isLeftParenthesis(elemPila)) {
                    postfixExp += elemPila;
                    elemPila = stack.pop();
                }
            } else if (isOperator(str)) {
                if (stack.isEmpty()) {
                    stack.push(str);
                } else {
                    String stackTop = stack.peek();

                    while (getPrecedence(stackTop, str).equals(stackTop) && !(stack.isEmpty())) {
                        postfixExp += stack.pop();
                        if (!(stack.isEmpty())) {
                            stackTop = stack.peek();
                        }
                    }
                    stack.push(str);
                }
            }
            else{
                this.ok = false;
                break;
            }
        }
        while (!(stack.isEmpty())) {
            postfixExp += stack.pop();
        }
        System.out.println("The postfix form of the expression you entered is: " + postfixExp);
    }


    /* Metodo que verifica si el parametro recibido es un operador.
     * @param ch el caracter a verificar si es o no operador.
     * @return true/false para indicar si es o no operador
     *
     */
    public static boolean isOperator(String ch) {
        String operators = "*.?+|";
        if (operators.indexOf(ch) != -1) {
            return true;
        } else {
            return false;
        }
    }

    /* Metodo que verifica si el parametro recibido es un parentesis derecho.
     * @param ch el caracter a verificar si es o no parentesis derecho.
     * @return true/false para indicar si es o no parentesis derecho.
     */
    public static boolean isRightParenthesis(String ch) {
        String operators = ")";

        if (operators.indexOf(ch) != -1) {
            return true;
        } else {
            return false;
        }
    }

    /* Metodo que verifica si el parametro recibido es un parentesis izquierdo.
     * @param ch el caracter a verificar si es o no parentesis izquierdo.
     * @return true/false para indicar si es o no parentesis izquierdo.
     */
    public static boolean isLeftParenthesis(String ch) {
        String operators = "(";

        if (operators.indexOf(ch) != -1) {
            return true;
        } else {
            return false;
        }
    }

    /* Metodo que verifica la precedencia de dos operadores.
     * @param op1 el primer operador a comparar.
     * @param op2 el segundo operador a comparar.
     * @return op1 si op1 es de mayor precedencia que op2.
     * @return op2 si op2 es de mayor precedencia que op1.
     */
    private String getPrecedence(String op1, String op2) {
        String nivel1Ops = "*+?";
        String nivel2Ops = ".";
        String nivel3Ops = "|";

        if (isLeftParenthesis(op1)) {
            return op2;
        } else if (isLeftParenthesis(op2)) {
            return op1;
        }

        if ((nivel1Ops.indexOf(op1) != -1) && (nivel1Ops.indexOf(op2) == -1)) {
            return op1;
        } else if ((nivel2Ops.indexOf(op1) != -1) && (nivel1Ops.indexOf(op2) != -1)) {
            return op2;
        } else if ((nivel2Ops.indexOf(op1) != -1) && (nivel3Ops.indexOf(op2) != -1)) {
            return op1;
        } else if ((nivel3Ops.indexOf(op1) != -1) && (nivel3Ops.indexOf(op2) == -1)) {
            return op2;
        } else {
            return op1;
        }

    }

    public String getPostfixExp() {
        return postfixExp;
    }
}

